package com.zhang.order.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhang.brand.entity.Brand;
import com.zhang.brand.service.IBrandService;
import com.zhang.common.dto.OrderLockStockDto;
import com.zhang.common.dto.UpdateSkuSaleCountDTO;
import com.zhang.common.exception.myexception.StateException;
import com.zhang.common.util.time.TimeUtils;
import com.zhang.goods.entity.SkuInfo;
import com.zhang.goods.entity.SkuSaleAttrValue;
import com.zhang.goods.entity.SpuInfo;
import com.zhang.goods.service.ISkuInfoService;
import com.zhang.goods.service.ISkuSaleAttrValueService;
import com.zhang.goods.service.ISpuInfoService;
import com.zhang.member.entity.MemberReceiveAddress;
import com.zhang.member.entity.MemberUser;
import com.zhang.member.service.IMemberReceiveAddressService;
import com.zhang.member.service.IMemberUserService;
import com.zhang.order.dto.OrderISaveItemDto;
import com.zhang.order.dto.OrderSaveDto;
import com.zhang.order.dto.UserEarningsDTO;
import com.zhang.order.entity.Order;
import com.zhang.order.entity.OrderItem;
import com.zhang.order.entity.OrderOperateHistory;
import com.zhang.order.enums.OrderStatusEnum;
import com.zhang.order.mapper.OrderMapper;
import com.zhang.order.service.IOrderItemService;
import com.zhang.order.service.IOrderOperateHistoryService;
import com.zhang.order.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhang.order.vo.*;
import com.zhang.warehouse.service.IWareSkuService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import static java.time.temporal.ChronoUnit.MINUTES;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author 创世神
 * @since 2023-12-05
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
    //    跨表操作能用sql解决就用sql，而不是注入太多的service
    @Autowired
    private ISkuInfoService skuInfoService;
    @Autowired
    private ISkuSaleAttrValueService skuSaleAttrValueService;
    @Autowired
    private ISpuInfoService spuInfoService;
    @Autowired
    private IBrandService brandService;
    @Autowired
    private IOrderItemService orderItemService;
    @Autowired
    private IMemberReceiveAddressService memberReceiveAddressService;
    @Autowired
    private IWareSkuService wareSkuService;
    @Autowired
    private IMemberUserService userService;
    @Autowired
    private IOrderOperateHistoryService orderOperateHistoryService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    private final String exchangeName="sku.sale.count.exchange";
    private final String queueName="sku.sale.count.elasticsearch.queue";

    @Override
    @Transactional
    public String saveOrder(OrderSaveDto dto) {
        long memberId = StpUtil.getLoginIdAsLong();
        MemberUser user = userService.getById(memberId);
        //生成订单编号
        Order order = new Order();
        order.setMemberUsername(user.getUserName());
        order.setStatus(OrderStatusEnum.NO_PAY.getStatusCode());//待收货
        order.setMemberId(memberId);
        order.setOrderType(dto.getOrderType());
        order.setCreateTime(TimeUtils.getLocalDateTimeStr());
        /*设置收货信息*/
        MemberReceiveAddress address = memberReceiveAddressService.getById(dto.getAddressId());
        order.setReceiverName(address.getName());
        order.setReceiverPhone(address.getPhone());
        order.setReceiverPostCode(address.getPostCode());
        order.setReceiverProvince(address.getProvince());
        order.setReceiverCity(address.getCity());
        order.setReceiverRegion(address.getRegion());
        order.setReceiverDetailAddress(address.getDetailAddress());
        order.setCreateTime(TimeUtils.getLocalDateTimeStr());
        /*计算价格*/
        order.setPayAmount(dto.getOrderPrice());
        save(order);
//         构建订单项:遍历生成 todo 如果有秒杀订单项最好构建为秒杀订单
        ArrayList<OrderItem> orderItems = new ArrayList<>();
        for (OrderISaveItemDto orderISaveItemDto : dto.getOrderISaveItemDtos()) {
            SkuInfo byId = skuInfoService.getById(orderISaveItemDto.getSkuId());
            List<SkuSaleAttrValue> skuSaleAttrValues = skuSaleAttrValueService.listBySkuId(byId.getId());
            SpuInfo spu = spuInfoService.getById(byId.getSpuId());
            OrderItem orderItem = new OrderItem();
            orderItem.setOrderId(order.getId());
            orderItem.setSkuId(orderISaveItemDto.getSkuId());
            orderItem.setCategoryId(byId.getCategoryId());
            orderItem.setSkuName(byId.getSkuName());
//            封装销售属性值为字符串
            StringBuilder attrValues = new StringBuilder();
            for (int i = 0; i < skuSaleAttrValues.size(); i++) {
                attrValues.append(skuSaleAttrValues.get(i).getAttrName());
                attrValues.append(":");
                attrValues.append(skuSaleAttrValues.get(i).getAttrValue());
//                如果是最后一个，就没有必要添加逗号了
                if (i < (skuSaleAttrValues.size() - 1)) {
                    attrValues.append(",");
                }
            }
            orderItem.setSkuAttrsVals(attrValues.toString());
            orderItem.setSkuPic(String.valueOf(byId.getSkuDefaultImg()));
            orderItem.setSpuId(byId.getSpuId());
            orderItem.setSpuName(spu.getSpuName());
//            如果是普通订单，则价格是原价，如果是其他活动的订单，则按活动价格
            if (order.getOrderType() == 0) {
                orderItem.setSkuPrice(byId.getPrice());
            } else {
                orderItem.setSkuPrice(orderISaveItemDto.getPrice());
            }
            orderItem.setSkuPrice(orderISaveItemDto.getPrice());
            Brand brand = brandService.getById(spu.getBrandId());
            orderItem.setSpuBrand(brand.getName());
            orderItem.setSkuQuantity(orderISaveItemDto.getBuyNumber());
            orderItems.add(orderItem);
        }
        List<OrderLockStockDto> collect = orderItems.stream().map(item -> {
            OrderLockStockDto stockDto = new OrderLockStockDto();
            stockDto.setSkuId(item.getSkuId());
            stockDto.setCount(item.getSkuQuantity());
            return stockDto;
        }).collect(Collectors.toList());
        //      如果是正常订单则锁定库存，如果是秒杀则不用
        if (dto.getOrderType() == 0) {
            wareSkuService.orderLockStock(collect);
        }
        orderItemService.saveBatch(orderItems);
        return String.valueOf(order.getId());
    }

    @Override
    public Page listByStatusAndUser(Map<String, String> queryMap) {
        long userId = StpUtil.getLoginIdAsLong();
        int status = Integer.parseInt(queryMap.get("status"));
        int pageNum = Integer.parseInt(queryMap.get("pageNum"));
        int pageSize = Integer.parseInt(queryMap.get("pageSize"));
        String keyWord = queryMap.get("keyWord");
//        Long timeBetween=Long.valueOf(String.valueOf(queryMap.get("timeBetween")));//时间差
        boolean isAdmin = StpUtil.getRoleList().contains("admin");
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        //-1表示查询所有
        if (status != -1) {
            wrapper.eq(Order::getStatus, status);
        }
        if (!isAdmin) {
            wrapper.eq(Order::getMemberId, userId);
        }
        if (!StrUtil.isBlank(keyWord)) {
            wrapper.eq(Order::getId, keyWord).or()
                    .eq(Order::getOrderSn, keyWord).or()
                    .eq(Order::getMemberId, keyWord);
        }
        return page(new Page<>(pageNum, pageSize), wrapper);
    }

    @Override
    public OrderDetailVo getOrderInfo(Long orderId) {
        OrderDetailVo orderDetailVo = new OrderDetailVo();
        Order byId = getById(orderId);
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime datetime_pattern = TimeUtils.parseLocalDateTime(byId.getCreateTime(), TimeUtils.DATETIME_PATTERN);
        long unitBetween = TimeUtils.getChronoUnitBetween(now, datetime_pattern, MINUTES);
//        如果订单是未支付状态，并且超过三十分钟，则将订单修改为失效状态,并且返还锁定库存
        if (byId.getStatus() == 0 && unitBetween > 30 && byId.getOrderType() == 0) {
            Order updateOrder = new Order();
            updateOrder.setId(orderId);
            updateOrder.setStatus(5);
            updateById(updateOrder);
            byId.setStatus(5);
//            返还锁定的库存
            for (OrderItem orderItem : orderItemService.getListByOrderId(orderId)) {
                wareSkuService.returnSkuStock(orderItem.getSkuId(), orderItem.getSkuQuantity());
            }
        }
//        秒杀订单3分钟关闭
        else if (byId.getStatus() == 0 && unitBetween > 3 && byId.getOrderType() == 1) {
            Order updateOrder = new Order();
            updateOrder.setId(orderId);
            updateOrder.setStatus(5);
            updateById(updateOrder);
            byId.setStatus(5);
//            TODO 返回库存
        }
        orderDetailVo.setOrderInfo(byId);
        List<OrderItem> list = orderItemService.getListByOrderId(orderId);
        orderDetailVo.setItems(list);
        return orderDetailVo;
    }


    @Override
    public void updateOrderToPay(Order order) {
        order.setStatus(1);//更改状态为已支付
        updateById(order);
        //添加订单操作记录
        OrderOperateHistory orderOperateHistory = new OrderOperateHistory();
        orderOperateHistory.setOrderId(order.getId());
        orderOperateHistoryService.addOrderPayHistory(orderOperateHistory);
//         扣除库存,更新sku售出字段
        for (OrderItem orderItem : orderItemService.getListByOrderId(order.getId())) {
            wareSkuService.deductStock(orderItem.getSkuId(), orderItem.getSkuQuantity());
            skuInfoService.saleSku(orderItem.getSkuId(), orderItem.getSkuQuantity());
        }

    }

    @Override
    public void receive(Long orderId) {
        //TODO 此处可以判断用户是否具有操作此订单的权限
        Order byId = getById(orderId);
        if (byId == null || byId.getStatus() != 2) {
            throw new RuntimeException();
        }
        byId.setStatus(OrderStatusEnum.IS_CLOSE.getStatusCode());//更改状态为已完成
        byId.setReceiveTime(LocalDateTime.now());
        updateById(byId);
        OrderOperateHistory orderOperateHistory = new OrderOperateHistory();
        orderOperateHistory.setOrderId(orderId);
        orderOperateHistoryService.addOrderReceiveHistory(orderOperateHistory);
    }

    @Override
    public void updateOrderToSend(String orderId) {
        Order byId = getById(orderId);
        if (byId == null || byId.getStatus() != 1) {
            throw new RuntimeException();
        }
        byId.setStatus(OrderStatusEnum.NO_SHIPPED.getStatusCode());
        byId.setDeliveryTime(LocalDateTime.now());
        updateById(byId);
        OrderOperateHistory orderOperateHistory = new OrderOperateHistory();
        orderOperateHistory.setOrderId(Long.valueOf(orderId));
        orderOperateHistoryService.addOrderSendHistory(orderOperateHistory);
    }

    @Override
    public List<OrderAppraiseVo> getOrderAppraise(String orderId) {
        Order byId = getById(orderId);
        if (OrderStatusEnum.IS_FINISH.getStatusCode().equals(byId.getStatus())) {
//            订单状态异常
            throw new StateException("订单");
        }
//        查询当前订单下的所有订单项
        List<OrderItem> orderItem = orderItemService.getListByOrderId(Long.valueOf(orderId));
//        遍历这些订单项，提取需要的参数，构造vo
        List<OrderAppraiseVo> orderAppraises = orderItem.stream().map(item -> {
            OrderAppraiseVo orderAppraise = new OrderAppraiseVo();
            orderAppraise.setOrderItemId(item.getId());
            orderAppraise.setOrderId(item.getOrderId());
            orderAppraise.setSkuId(item.getSkuId());
            orderAppraise.setSkuImg(item.getSkuPic());
            orderAppraise.setSkuSpecs(item.getSkuAttrsVals());
            if (item.getSkuPrice() != null || item.getSkuQuantity() != null) {
                orderAppraise.setTotalPrice(item.getSkuPrice().doubleValue() * item.getSkuQuantity().doubleValue());
            }
            return orderAppraise;
        }).collect(Collectors.toList());
        return orderAppraises;
    }

    @Override
    public void orderFinish(Order order) {
        order.setCommentTime(LocalDateTime.now());
        order.setStatus(OrderStatusEnum.IS_CLOSE.getStatusCode());
        updateById(order);
        /* 找到sku销量字段增加*/
        List<OrderItem> listByOrderId = orderItemService.getListByOrderId(order.getId());
        listByOrderId.forEach(item -> {
            SkuInfo byId = skuInfoService.getById(item.getSkuId());
            long l = Long.parseLong(byId.getSaleCount()) + Long.valueOf(item.getSkuQuantity());
            UpdateSkuSaleCountDTO updateSkuSaleCountDTO = new UpdateSkuSaleCountDTO(byId.getId().toString(), (int) l);
//             修改elasticsearch中的sku的销售量
            rabbitTemplate.convertAndSend(exchangeName,queueName, JSON.toJSON(updateSkuSaleCountDTO));
            byId.setSaleCount(Long.toString(l));
            skuInfoService.updateById(byId);
        });
        OrderOperateHistory orderOperateHistory = new OrderOperateHistory();
        orderOperateHistory.setOrderId(order.getId());
        orderOperateHistory.setOrderStatus(OrderStatusEnum.IS_CLOSE.getStatusCode());
        orderOperateHistoryService.addOrderAppraiseHistory(orderOperateHistory);
    }

    @Override
    public UserEarningsVO userEarnings(Long loginUser) {
//        TODO 此处最好判断是否具有权限而不是角色,需要实现根据给定范围选择汇总：按年汇总，按月汇总，按日汇总，
        if (StpUtil.hasRole("admin")) {
            loginUser = null;
        }
        UserEarningsVO userEarningsVO = new UserEarningsVO();
        List<UserEarningsDTO> userEarningsDTOS = this.baseMapper.getUserEarnings(loginUser);
        /* 遍历封装对象*/
//        将年份相同的汇总
        EarningLineItem earningLineItem = new EarningLineItem();
        ArrayList<String> xA = new ArrayList<>();
        ArrayList<Double> values = new ArrayList<>();
        userEarningsDTOS.stream()
                .collect(Collectors.groupingBy(
                        UserEarningsDTO::getOrderTime,
                        ConcurrentHashMap::new,//线程安全
                        Collectors.summingDouble(UserEarningsDTO::getTotalAmount))
                ).forEach((key, value) -> {
                    values.add(value);
                    xA.add(key);
                });
        earningLineItem.setXAxis(xA);
        earningLineItem.setValues(values);
        List<PieItem> collect = userEarningsDTOS.stream()
                .collect(Collectors.groupingBy(
                        UserEarningsDTO::getSkuId,
                        ConcurrentHashMap::new,//线程安全
                        Collectors.summingDouble(UserEarningsDTO::getTotalAmount))
                ).entrySet().stream().map(entry -> {
                    PieItem pieItem = new PieItem();
                    pieItem.setName(entry.getKey());
                    pieItem.setValue(entry.getValue().toString());
                    return pieItem;
                }).collect(Collectors.toList());
        userEarningsVO.setPieItems(collect);
        userEarningsVO.setEarningLineItem(earningLineItem);
        return userEarningsVO;
    }
}
